import axios, { CreateAxiosDefaults, AxiosInstance, RawAxiosRequestConfig } from 'axios';
import { App } from 'vue';

type AnyObject = {
  [propName: string]: any;
};

interface RequestPreprocessor {
  (config: RawAxiosRequestConfig): RawAxiosRequestConfig;
}

interface DataParser {
  (data: any): any;
}

interface HttpRestfulApiOptions extends CreateAxiosDefaults<any> {
  /** API名称 */
  name: string;
  /** API基地址 */
  baseURL: string;
  /** 
   * 请求参数预处理器，用于对请求配置项进行修改
   * @param config axios的请求配置项，具体见axios文档
   */
  preprocessor?: RequestPreprocessor,
  /** 
   * 响应数据解析器，用于对返回数据进行解析和错误处理
   * @param data axios请求完成后的json数据，有可能是undefined
   */
  parser?: DataParser
}

interface HttpMethodFunc {
  /** 
   * 按指定http方法向api接口发送请求
   * 
   * @param url 请求相对地址
   * @param query url查询参数json
   * @param data 请求体json数据
   * @returns 经parser解析后的响应数据，出错时为undifined
   */
  (url: string, query?: AnyObject, data?: AnyObject): Promise<AnyObject>;
}

interface HttpRestfulApi {
  /** API名称 */
  name: string;
  /** API创建时的配置项 */
  options: HttpRestfulApiOptions;
  get: HttpMethodFunc;
  put: HttpMethodFunc;
  post: HttpMethodFunc;
  patch: HttpMethodFunc;
  delete: HttpMethodFunc;
}

const defaultPreprocessor: RequestPreprocessor = config => {
  return config;
};

const defaultParser: DataParser = data => {
  return data;
};

const execAndParse = async (service: AxiosInstance, config: RawAxiosRequestConfig, preprocessor = defaultPreprocessor, parser = defaultParser) => {
  let result = undefined;
  try {
    config = preprocessor(config);
    const res = await service.request(config);
    result = parser(res.data);
  } catch (err: any) {
    result = undefined;
    console.log(err);
    ElMessage.error({
      message: err.message,
    });
  }
  return result;
};

/**
 * 创建指定名称的api调用模块
 *
 * @param options API配置项
 * @returns vue app 插件方法
 */
const createApi = (options: HttpRestfulApiOptions) => (app: App) => {
  const apiService = axios.create(options);

  const api: HttpRestfulApi = {
    name: options.name,
    options: options,
    get: async (url, query?, data?) => {
      return await execAndParse(apiService, { method: 'get', url, params: query, data }, options.preprocessor, options.parser);
    },
    post: async (url, query?, data?) => {
      return await execAndParse(apiService, { method: 'post', url, params: query, data }, options.preprocessor, options.parser);
    },
    put: async (url, query?, data?) => {
      return await execAndParse(apiService, { method: 'put', url, params: query, data }, options.preprocessor, options.parser);
    },
    patch: async (url, query?, data?) => {
      return await execAndParse(apiService, { method: 'patch', url, params: query, data }, options.preprocessor, options.parser);
    },
    delete: async (url, query?, data?) => {
      return await execAndParse(apiService, { method: 'delete', url, params: query, data }, options.preprocessor, options.parser);
    },
  };
  app.provide(`api-${options.name}`, api);
};

/**
 * 获取指定名称的API调用模块
 *
 * @param name 要使用的API名称，与创建时相一致
 * @returns 指定名称的API调用模块
 */
const useApi = (name: string) => {
  return inject(`api-${name}`) as HttpRestfulApi;
};

export { createApi, useApi, };
export type { HttpMethodFunc, HttpRestfulApiOptions, HttpRestfulApi };
